package com.yet.container.registry.redis;

import java.util.function.Consumer;
import java.util.function.Function;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;

//@ConfigurationProperties(prefix = "yet.redis", ignoreUnknownFields = true)
public class JedisOperater {

	private static final Logger logger = LoggerFactory.getLogger(JedisOperater.class);
	private String uri;
	private String host;// redis服务器ip
	private int port;// redis防火墙端口
	private String pwd; // redis密码，通过服务器里redis配置文件里设置
	private int maxTotal = 300;// 最大连接数
	private int maxIdle = 200;// 最大空闲连接数
	// 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出
	private int maxWait = 200;
	private int timeout = 20000;
	// 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
	private boolean testOnBorrow = false;
	private JedisPool jedisPool;

	private void initPool() {
		boolean conn = StringUtils.isNotBlank(uri) || (StringUtils.isNotBlank(host) && port != 0);
		try {
			if (!conn) {
				throw new IllegalArgumentException("连接信息不能为空");
			}
			JedisPoolConfig config = new JedisPoolConfig();
			config.setMaxTotal(maxTotal);
			config.setMaxIdle(maxIdle);
			config.setMaxWaitMillis(maxWait);
			config.setTestOnBorrow(testOnBorrow);
			if (StringUtils.isNotBlank(uri)) {
				parseUri(uri);
			}
			jedisPool = new JedisPool(config, host, port, timeout, pwd, Protocol.DEFAULT_DATABASE);
		} catch (Exception e) {
			logger.error("Redis注册中心[{}] 启动失败:{}", this.uri, e);
			throw new IllegalStateException("Redis注册中心[" + this.uri + "] 启动失败", e);
		}
	}

	// 获取jedis实例
	public synchronized Jedis getJedis() {
		// 连接池中获取资源
		try {
			Jedis jedis = jedisPool.getResource();
			return jedis;
		} catch (Exception e) {
			throw new IllegalStateException("Jedis get failed", e);
		}
	}

	// 获取jedis实例
	public synchronized void getJedisAndConsumer(Consumer<Jedis> consumer) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			consumer.accept(jedis);
		} catch (Exception e) {
			throw new IllegalStateException("Jedis get failed ", e);
		} finally {
			release(jedis);
		}
	}

	// 获取jedis实例
	public synchronized <R> R getJedisAndFunction(Function<Jedis, R> function) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			return function.apply(jedis);
		} catch (Exception e) {
			throw new IllegalStateException("Jedis get failed ", e);
		} finally {
			release(jedis);
		}
	}

	public void release(final Jedis jedis) {
		if (jedis != null) {
			jedis.close();
		}
	}

	public void start() {
		initPool();
	}

	public void close() {
		if (jedisPool != null) {
			this.jedisPool.close();
		}
	}

	private void parseUri(String uri) {
		try {
			String[] parts = extractParts(uri);
			String host = parts[0];
			int port = Integer.valueOf(parts[1]);
			this.host = StringUtils.isNotBlank(this.host) ? this.host : host;
			this.port = this.port != 0 ? Integer.valueOf(this.port) : port;
		} catch (NumberFormatException ex) {
			throw new IllegalArgumentException(ex);
		}
	}

	public static String[] extractParts(String from) {
		int idx = from.lastIndexOf(":");
		String host = idx != -1 ? from.substring(0, idx) : from;
		String port = idx != -1 ? from.substring(idx + 1) : "";
		return new String[] { host, port };
	}

	public String getUri() {
		return uri;
	}

	public void setUri(String uri) {
		this.uri = uri;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public int getMaxTotal() {
		return maxTotal;
	}

	public void setMaxTotal(int maxTotal) {
		this.maxTotal = maxTotal;
	}

	public int getMaxIdle() {
		return maxIdle;
	}

	public void setMaxIdle(int maxIdle) {
		this.maxIdle = maxIdle;
	}

	public int getMaxWait() {
		return maxWait;
	}

	public void setMaxWait(int maxWait) {
		this.maxWait = maxWait;
	}

	public int getTimeout() {
		return timeout;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public boolean isTestOnBorrow() {
		return testOnBorrow;
	}

	public void setTestOnBorrow(boolean testOnBorrow) {
		this.testOnBorrow = testOnBorrow;
	}

	public JedisPool getJedisPool() {
		return jedisPool;
	}

	public void setJedisPool(JedisPool jedisPool) {
		this.jedisPool = jedisPool;
	}

}